package com.tianji.learning.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.api.dto.leanring.LearningRecordFormDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.pojo.po.LearningLesson;
import com.tianji.learning.pojo.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.util.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler taskHandler;

    /**
     * 查询当前用户指定课程的学习进度
     *
     * @param courseId 课程id
     * @return 课表信息、学习记录及进度信息
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        // 查询课程信息
        LearningLesson lesson = lessonService.getLearningLesson(courseId);
        AssertUtils.isNotNull(lesson, "课程不存在");

        // 查询课程计划列表
        List<LearningRecord> recordList = lambdaQuery()
                // .eq(LearningRecord::getUserId, UserContext.getUser())  // 通过lesson可以确定用户和课程
                .eq(LearningRecord::getLessonId, lesson.getId())
                .list();

        LearningLessonDTO lessonDTO = new LearningLessonDTO();
        lessonDTO.setId(lesson.getId());
        lessonDTO.setLatestSectionId(lesson.getLatestSectionId());

        List<LearningRecordDTO> recordDTOS = BeanUtils.copyList(recordList, LearningRecordDTO.class);
        lessonDTO.setRecords(recordDTOS);

        return lessonDTO;
    }

    /**
     * 提交学习记录
     *
     * @param formDTO formDTO
     */
    @Override
    @Transactional
    public void addLearningRecord(LearningRecordFormDTO formDTO) {
        Integer sectionType = formDTO.getSectionType();

        boolean finished = false;
        // 分类型处理考试和视频，如果所有小节已完成，同义进行处理
        if (SectionType.EXAM.equalsValue(sectionType)) {
            // 考试 新增学习记录，已学习小节 +1
            finished = handleExamRecord(formDTO);
        } else if (SectionType.VIDEO.equalsValue(sectionType)) {
            finished = handleVideoRecord(formDTO);
        }

        if(!finished && formDTO.getDuration() == -1){
            return;
        }

        // 所有小节已完成学习后的处理
        handleLearningLessonChange(formDTO, finished);
    }

    /**
     * 所有小节已完成学习后的处理
     *
     * @param formDTO
     * @param finished
     */
    private void handleLearningLessonChange(LearningRecordFormDTO formDTO, boolean finished) {
        // 对于新完成的小节，修改的是课表中已学习小节数量
        LearningLesson lesson = lessonService.getById(formDTO.getLessonId());
        if (ObjectUtil.isEmpty(lesson)) {
            throw new BizIllegalException("课程不存在，无法更新数据！");
        }

        boolean allFinished = false;
        if (finished) {
            // 查询该课程总小节信息
            CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if (ObjectUtil.isEmpty(cInfo)) {
                throw new BizIllegalException("课程不存在，无法更新数据！");
            }

            allFinished = lesson.getLearnedSections() + 1 >= cInfo.getSectionNum();
        }

        // 如果该小节完成，已完成小节数量+1
        // 如果全部完成需要修改课程状态为已完成
        lessonService.lambdaUpdate()
                .set(lesson.getStatus().getValue() == LessonStatus.NOT_BEGIN.getValue(), LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .set(allFinished, LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                // 默认false，如果发生修改表示有新的小节完成
                .set(!finished, LearningLesson::getLatestSectionId, formDTO.getSectionId())
                .set(!finished, LearningLesson::getLatestLearnTime, formDTO.getCommitTime())
                .setSql(finished, "learned_sections = learned_sections + 1")
                .eq(LearningLesson::getId, lesson.getId())
                .update();

    }

    /**
     * 处理视频，需要判断是否学完
     *
     * @param formDTO
     * @return
     */
    private boolean handleVideoRecord(LearningRecordFormDTO formDTO) {
        // 查询旧的学习记录，有则更新，没有则新建
        LearningRecord learningRecord = queryOldRecord(formDTO.getLessonId(), formDTO.getSectionId());

        // 不存在则新增
        if (ObjectUtil.isNull(learningRecord)) {
            LearningRecord record = BeanUtils.copyBean(formDTO, LearningRecord.class);
            record.setUserId(UserContext.getUser());
            boolean success = save(record);
            if (!success) {
                throw new DbException("新增学习记录失败！");
            }
            return false;
        }

        // 已存在则更新
        boolean finished = !learningRecord.getFinished() && formDTO.getMoment() * 2 >= formDTO.getDuration();

        if (!finished) {
            LearningRecord record = BeanUtils.copyBean(formDTO, LearningRecord.class);
            record.setId(learningRecord.getId());
            record.setFinished(learningRecord.getFinished());
            record.setFinished(learningRecord.getFinished());
            taskHandler.addLearningRecord(record);
            formDTO.setDuration(-1);
            return false;
        }

        boolean update = lambdaUpdate()
                .set(LearningRecord::getFinished, true)
                .set(LearningRecord::getFinishTime, formDTO.getCommitTime())
                .set(LearningRecord::getMoment, formDTO.getMoment())
                .eq(LearningRecord::getId, learningRecord.getId())
                .update();

        if (!update) {
            throw new DbException("更新学习记录失败！");
        }

        // 数据更新后清理缓存
        taskHandler.cleanRecordCache(formDTO.getLessonId(), formDTO.getSectionId());
        return true;
    }

    /**
     * 处理考试，小节直接完成，保存学习记录,后续判断所有小节是否全部完成
     *
     * @param formDTO
     * @return
     */
    private boolean handleExamRecord(LearningRecordFormDTO formDTO) {
        LearningRecord record = BeanUtils.copyBean(formDTO, LearningRecord.class);
        record.setUserId(UserContext.getUser());
        record.setFinished(true);
        record.setFinishTime(formDTO.getCommitTime());
        boolean save = save(record);
        if (!save) {
            throw new DbException("新增考试的学习记录失败");
        }
        return true;
    }

    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
        // 1.查询缓存
        LearningRecord record = taskHandler.readRedisData(lessonId, sectionId);
        // 2.如果命中，直接返回
        if (record != null) {
            return record;
        }
        // 3.未命中，查询数据库
        record = lambdaQuery()
                .eq(LearningRecord::getUserId, UserContext.getUser())
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        if (ObjectUtil.isEmpty(record)) {
            return null;
        }
        // 4.写入缓存
        taskHandler.writeRecordCache(record);
        return record;
    }


}
